package com.miyu.client1.utils.bookUtils;

import lombok.SneakyThrows;
import org.apache.commons.lang.StringUtils;
import us.codecraft.webmagic.Page;
import us.codecraft.webmagic.selector.Selectable;

import java.lang.reflect.Method;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 解析规则加返回数据处理
 * 三段处理 例如： class.test.
 */
public class JXPageUtils {

    private static JXPageUtils invoke= new JXPageUtils();


    /**
     * 解析列表数据 返回Selectable
     * 一般处理列表数据使用
     * @param page
     * @param ruleStr
     * @return
     */
    static List<Selectable>  JXPageRuleByPage(Page page,String ruleStr){
        List<Selectable> nodes=null;
        String[] rtg = ruleStr.split("&");
        String [] num = rtg[0].split("\\.");
        if(num.length==3){
            //重组规则 //移除第一组最后一位
            ruleStr = num[0]+"."+num[1];
            for (int i=1;i<rtg.length;i++){
                ruleStr +="&"+rtg[i];
            }

            nodes  = page.getHtml().xpath(JXRleCommon(ruleStr)).nodes();
            //由于列表取值取值不一定从第一个开始 所以增加从指定位置开始
            if(nodes.size()>Integer.valueOf(num[2])){
                nodes = nodes.subList(Integer.valueOf(num[2]),nodes.size());
            }
        }else {
            nodes  = page.getHtml().xpath(JXRleCommon(ruleStr)).nodes();
        }
        return nodes;
    }

    /**
     * 正常解析数据 tg.sp(0@3)&lp(:@1)tg.rp(#nbsp@"")
     * 字符截取规则 tg.sp(0@2) 字符取substring(0,2)取值,
     * tg.lp(.@1) 指 split(".")分割取 第一个 & 符 合并取值 暂不做复杂处理 tg.sp()&lp() 格式
     * tg.rp(ces@ts) 指 replace('ce','ts')字符替换做指定字符替换
     * tg.lk(.@0)//由此包含 取连接地址
     * tg.sp(0@2) 字符取substring(0,2)取值
     * 规则说明  //[class='test']/p[1]|tg&lg(:)
     / * @param stable
     * @param ruleStr
     * @return
     */
    public static String JXPageRuleByTable(Selectable stable, String ruleStr) throws Exception {
        String rs="";
        if(StringUtils.isBlank(ruleStr))
            return rs;
        if(JXRleCommon(ruleStr).indexOf("%")>-1){
            rs = stable.xpath(JXRleCommon(ruleStr).replace("%","")).links().get();
        }else{
            rs = stable.xpath(JXRleCommon(ruleStr)).toString();
        }
        String[] rtg = ruleStr.split("\\|");
        if(rtg.length>1){
            for (int i = 1; i < rtg.length; i++) {
                //附加规则解析 处理根据xpath取出的之再次进行处理
                //eg tg.rp()&tg.lg)|tg.rp()&tg.lg)
                //&和| 区别 可多个标签使用拼接使用 &一个字符规则组合取值 | 同一个字符按顺序处理
                String ps=rs;
                rs="";
                String [] s = rtg[i].split("&"); //
                for (int z=0;z<s.length;z++){
                    String mothod = s[z].substring(3,s[z].indexOf("("));
                    rs+=(String) invoke.getClass().getMethod(mothod,new Class[]{ String.class, String.class }).invoke(invoke,new Object[]{s[z],ps});
                }
            }
        }
        return rs;
    }

    public static String  JXPageRuleByCheckRule(Page page,String ruleStr) throws Exception{
        String rs="";

        if(StringUtils.isBlank(ruleStr))
            return rs;
        if(JXRleCommon(ruleStr).indexOf("%")>-1){
            rs = page.getHtml().xpath(JXRleCommon(ruleStr).replace("%","")).links().get();
        }else{
            rs = page.getHtml().xpath(JXRleCommon(ruleStr)).toString();
        }

        String[] rtg = ruleStr.split("\\|");
        if(rtg.length>1){
            for (int i = 1; i < rtg.length; i++) {
                //附加规则解析 处理根据xpath取出的之再次进行处理
                //eg tg.rp()&tg.lg)|tg.rp()&tg.lg)
                //&和| 区别 可多个标签使用拼接使用 &一个字符规则组合取值 | 同一个字符按顺序处理
                String ps=rs;
                rs="";
                String [] s = rtg[i].split("&"); //
                for (int z=0;z<s.length;z++){
                    String mothod = s[z].substring(3,s[z].indexOf("("));
                    rs+=(String) invoke.getClass().getMethod(mothod,new Class[]{ String.class, String.class }).invoke(invoke,new Object[]{s[z],ps});
                }
            }
        }
        return rs;
    }

    /**
     * 公共解析规则 返回字符串
     * @param ruleSet
     * @return
     */
    @SneakyThrows
    public static String JXRleCommon(String ruleSet){
        StringBuffer rt = new StringBuffer();
        StringBuffer pt = new StringBuffer();
        //区分取值和附加条件对取值进行处理
        String[] rtg = ruleSet.split("\\|");
        String rule = rtg[0];//正常规则处理 返回string
        for(int x=0;x<rtg.length;x++){
            if(x==0){
                //判断 规则取值 id.|#| class.|.| 同源   tag.标签
                String [] s = rtg[0].split("&"); //& 可多个标签使用拼接使用
                for (int i = 0; i < s.length; i++) {
                    String [] l = s[i].split("\\.");//单个取值替换判断
                    if (l[0].equals("tag")){
                        switch (l.length){
                            case 1:
                                break;
                            case 2:
                                rt.append("//").append(l[1]);
                                break;
                            case 3:
                                //判断最有一位书否取值 @ 取值
                                String [] m = l[2].split("@");
                                switch (m.length){
                                    case 1:
                                        rt.append("//").append(l[1]).append("[").append(m[0]).append("]");
                                        break;
                                    case 2:
                                        String ts = m[1];
                                        if(ts.equals("text")){
                                            ts = "/text()";
                                        }else if(ts.equals("href")){
                                            //特殊化处理 由于直接去href 不能够出去当前完整连接 所以增加特殊标识 一做判断 执行时在去掉
                                            ts = "%";
                                        }else {
                                            ts = "/@"+m[1];
                                        }
                                        rt.append("//").append(l[1]).append("[").append(m[0]).append("]");
                                        rt.append(ts);
                                        break;
                                    default:break;
                                }
                                break;
                            default :
                                break;
                        }
                    }else{
                        switch (l.length){
                            case 1:
                                break;
                            case 2:
                                //判断最有一位书否取值 @ 取值
                                String [] st = l[1].split("@");
                                switch (st.length){
                                    case 1:
                                        rt.append("//[ @").append(l[0]).append("='").append(l[1]).append("']");
                                        break;
                                    case 2:
                                        String ts = st[1];

                                        if(ts.equals("text")){
                                            ts = "/text()";
                                        }else{
                                            ts = "/@"+st[1];
                                        }
                                        rt.append("//[ @").append(l[0]).append("='").append(st[0]).append("']")
                                                .append(ts);
                                        break;
                                    default:
                                         rt.append("//[ @").append(l[0]).append("='").append(l[1]).append("']");
                                }

                                break;
                            case 3:
                                //判断最有一位书否取值 @ 取值
                                String [] m = l[2].split("@");
                                switch (m.length) {
                                    case 1:
                                        rt.append("//[ @").append(l[0]).append("='").append(l[1]).append("']").append("/[").append(m[0]).append("]");
                                        break;
                                    case 2:
                                        String ts = m[1];
                                        if(ts.equals("text")){
                                            ts = "/text()";
                                        }else{
                                            ts = "/@"+m[1];
                                        }
                                        rt.append("//[ @").append(l[0]).append("='").append(l[1]).append("']").append("[").append(m[0]).append("]")
                                                .append(ts);
                                        break;
                                    default:
                                        break;
                                }

                                break;
                            default :
                                break;
                        }
                    }
                }
            }

        }
        return rt.toString();
    }


    /**
     * tg.lp(.@1) 指分割 split(".")分割取 第一个 & 符
     * tg.rp(ces@ts) 指替换 replace('ce','ts')字符替换做指定字符替换
     * tg.lk(.@0)//由此包含 取连接地址
     * tg.sp(0@2) 指字符取 substring(0,2)取值
     * @param lp
     * @param st
     * @return
     */
    private static String  regex = "\\(([^}]*)\\)";//匹配小括号

    /**
     * 分割取值
     * @param str
     * @param obj
     * @return
     */
    public String lp (String str,String obj){
        String rs="";
        //取括号内容 之后再分割 取值
        Pattern compile = Pattern.compile(regex);
        Matcher matcher = compile.matcher(str);
        String group="";
        while(matcher.find()){
            group = matcher.group(1);
        }
        String [] s = group.split("@");
        String [] lpStr = obj.split(s[0]);
        rs = lpStr[1];

        return rs;
    }

    /**
     * 截取取值
     * 第二个值不大于0 则从后取值
     * @param str
     * @param obj
     * @return
     */
    public String sp(String str,String obj){
        String rs="";
        //取括号内容 之后再分割 取值
        Pattern compile = Pattern.compile(regex);
        Matcher matcher = compile.matcher(str);
        String group="";
        while(matcher.find()){
            group = matcher.group(1);
        }
        String [] s = group.split("@");
        switch (s.length){
            case 1:
                //取后几位数据 同理第一为空 第二个为符
                rs = obj.substring(Integer.valueOf(s[0]),obj.length());
                break;
            case 2:
                if (StringUtils.isBlank(s[0])){
                    if(Integer.valueOf(s[1])<=0){
                        rs = obj.substring(obj.length()-Math.abs(Integer.valueOf(s[1])),obj.length());
                    }else
                        rs = obj.substring(0,Math.abs(Integer.valueOf(s[1])));

                }else{
                    if(Integer.valueOf(s[1])>0)
                        rs = obj.substring(Integer.valueOf(s[0]),Integer.valueOf(s[1]));
                    else
                        rs = obj.substring(Integer.valueOf(s[0]),obj.length()-Math.abs(Integer.valueOf(s[1])));
                }
                break;
            default:break;
        }
        return rs;
    }

    /**
     * 字符替换 $ 符替换空格 解决 替换文本中换行符<br>
     * @param str
     * @param obj
     * @return
     */
    public String rp(String str,String obj){
        String rs="";
        //取括号内容 之后再分割 取值
        Pattern compile = Pattern.compile(regex);
        Matcher matcher = compile.matcher(str);
        String group="";
        while(matcher.find()){
            group = matcher.group(1);
        }
        String [] s = group.split("@");
        if(s[0].indexOf("$")>-1)
            //rs = obj.replace(s[0].replace("$"," "),s[1].replace("$"," "));
              rs = obj.replace(s[0].replace("$"," "),s[1].replace("$","&nbsp"));
        else
            rs = obj.replace(s[0],s[1]);
        return rs;
    }


}